/************************************************************
 * Copyright (C), 2022-2030, ripnano. Co., Ltd.
 * FileName:        can_device.h
 * Author:          Dan Yin
 * Date:            2023-05-12
 * Description:     the class of CAN bus device
 * Version:         1.0.0.0
 **********************************************************/

#ifndef CAN_DEVICE_H
#define CAN_DEVICE_H

// add necessary includes here
#include <QObject>
#include <QDebug>
#include <QCanBus>
#include <QCanBusDevice>
#include <QMutex>
#include <QMutexLocker>
#include <QSemaphore>
#include <QCoreApplication>
#include <QTimer>

#include "cycle_buffer.h"
#include "share_function.h"
#include "defines/def_frame_protocol.h"

#ifdef QT_BITRATE_500K
#define DEF_BITRATE          500000     // T4: 500000;
#else
#define DEF_BITRATE          250000     // T3: 250000;
#endif

class CanDevice : public QObject
{
    Q_OBJECT
private:
    typedef QPair<QCanBusDevice::ConfigurationKey, QVariant> parBusConfigItem;

    struct ST_CAN_SETTING {
        QString sPluginName;
        QString sDevInterface;
        QList<parBusConfigItem> lstCanConfig;

        ST_CAN_SETTING() {
            sPluginName = "";
            sDevInterface = "";
            lstCanConfig.clear();
        }
    };

public:
    // Get an instance of "CanDevice" class, if exist, return it
    static CanDevice* getInstance(QObject *pParent = nullptr);

    // The default destructor
    virtual ~CanDevice();

    // open a CAN bus
    int openCAN();

    // close a CAN bus
    void closeCAN();

    // send an frame data to CAN bus
    int sendFrameData(int nFrameId, const QByteArray &baFrameData, bool bQueued);

signals:
    // the signal that received data from CAN
    void signalFramesReceived(unsigned int unCanId, QByteArray baPayload);

private slots:
    // An CAN bus error occurs
    void slotErrorOccurred(QCanBusDevice::CanBusError error) const;

    // One or more frames have been received by the CAN bus
    void slotFramesReceived();

    // A payload of frames has been written to the CAN bus
    void slotFramesWritten(qint64 nFramesCount);

    // State changed on the CAN bus
    void slotStateChanged(QCanBusDevice::CanBusDeviceState stateCan);

    // write data to COM
    void slotSendDataTimer();

private:
    // The default constructor
    explicit CanDevice(QObject *parent = nullptr);

    // After constructing object, initialize the object
    void _initialze();

    // the command handler
    void _commandHandler();

    // Send a frame data
    int _sendFrameData(int nFrameId, const QByteArray &baFrameData);

private:
    QCanBusDevice       *m_pCanDevice = nullptr;
    ST_CAN_SETTING      m_stCanSetting;

    mutable QMutex      m_mtxSend;
    mutable QMutex      m_mtxRecv;

    QTimer              *m_pWriteDataTimer = nullptr;
};

#endif // CAN_DEVICE_H
